package com.atguigu.feature.stream;

import com.atguigu.feature.entity.Employee;
import org.junit.Test;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * Created by Smexy on 2024/4/2
 */
public class DemoTestStream {

    @Test
    public void testStream01() {
        List<Employee> employeeList = new ArrayList<>();
        employeeList.add(new Employee(1, "tom", 5000.00d));
        employeeList.add(new Employee(2, "jerry", 6000.00d));
        employeeList.add(new Employee(3, "harry", 7000.00d));
        employeeList.add(new Employee(4, "bob", 8000.00d));
        employeeList.add(new Employee(5, "kate", 9000.00d));
        employeeList.add(new Employee(6, "mary", 9100.00d));
        employeeList.add(new Employee(7, "jim", 9200.00d));
        employeeList.add(new Employee(8, "white", 9300.00d));
        employeeList.add(new Employee(9, "black", 9400.00d));

        // 需求：先给所有人的工资乘以10，然后筛选出工资大于90000且名字中有"a"的员工
        employeeList.stream()
                .map(employee -> {
                    Double empSalary = employee.getEmpSalary();
                    employee.setEmpSalary(empSalary * 10);
                    return employee;
                }).filter(employee -> employee.getEmpSalary() > 90000 && employee.getEmpName().contains("a"))
                .forEach(employee -> System.out.println("employee = " + employee));
    }

    @Test
    public void testCreateStream01() {
        List<String> list = Arrays.asList("a", "bb", "ccc");

        // 根据集合创建 Stream 对象
        // 串行执行操作
        Stream<String> stream = list.stream();
        System.out.println("stream = " + stream);

        // 并行执行操作
        Stream<String> parallelStream = list.parallelStream();
        System.out.println("parallelStream = " + parallelStream);
    }

    @Test
    public void testCreateStream02() {
        Stream.iterate(1, n -> n + 1).forEach(value -> System.out.println(value));
    }

    @Test
    public void testFilter() {
        List<Integer> numberList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);

        numberList.stream()     // [创建 Stream 对象]
                // .filter(number -> {return number % 2 == 0;}) [中间操作] number 是遍历集合得到的每一个对象，把符合条件的对象保留下来生成新 Stream
                .filter(number -> number % 2 == 0)  // [中间操作] number 是遍历集合得到的每一个对象，把符合条件的对象保留下来生成新 Stream
                // ; 如果没有终结操作，那么中间操作就不会执行
                .forEach(number -> System.out.println(number));
    }

    @Test
    public void testPeek() {
        List<Integer> numberList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);

        long count = numberList.stream()
                .peek(number -> System.out.println(number)) // 和 forEach() 区别是，peek()是中间操作，forEach()是终结操作
                .count(); // 终结操作，返回当前 Stream 中还有多少个集合数据

        System.out.println("count = " + count);
    }

    @Test
    public void testSorted() {
        List<Integer> numberList = Arrays.asList(2, 3, 5, 7, 9, 8, 4);

        numberList.stream() // 创建 Stream 对象
                .sorted()  // 中间操作，执行排序，内部排序
                .forEach(number -> System.out.print(number));

        System.out.println("----------------");
        // Stream 操作不会改变原来集合的数据
        System.out.println(numberList);
    }

    @Test
    public void testMap() {
        List<String> strList = Arrays.asList("a", "bb", "ccc", "dddd", "eeeee");

        strList.stream() // 创建 Stream 对象

                // 中间操作：映射
                .map(str -> {   // 这里传入的 str 是遍历集合得到的每一个元素
                    return str.length(); // 这里返回 str 的长度
                    // 怎么理解映射呢？
                    // 输入数据：集合中的每一个元素，这里是字符串
                    // 输出数据：新数据，这里是字符串的长度
                    // 所谓映射就是根据输出的数据组成了一个新的集合
                })
                .forEach(len -> System.out.println(len));
    }

    @Test
    public void testEmpListToSalaryList() {
        // 需求：把员工集合映射为员工工资的集合
        List<Employee> employeeList = new ArrayList<>();
        employeeList.add(new Employee(1, "tom", 5000.00d));
        employeeList.add(new Employee(2, "jerry", 6000.00d));
        employeeList.add(new Employee(3, "harry", 7000.00d));
        employeeList.add(new Employee(4, "bob", 8000.00d));
        employeeList.add(new Employee(5, "kate", 9000.00d));
        employeeList.add(new Employee(6, "mary", 9100.00d));
        employeeList.add(new Employee(7, "jim", 9200.00d));
        employeeList.add(new Employee(8, "white", 9300.00d));
        employeeList.add(new Employee(9, "black", 9400.00d));

        employeeList.stream()
                .map(employee -> {
                    return employee.getEmpSalary();
                })
                .forEach(salary -> System.out.println(salary));
    }

    @Test
    public void testCount() {
        List<Integer> numberList = Arrays.asList(2, 3, 5, 7, 9, 8, 4);

        long count = numberList.stream()
                .filter(number -> number % 2 == 0)
                .count(); // 终结操作，执行完前面的操作之后，Stream 中还剩多少个元素

        System.out.println("count = " + count);
    }

    @Test
    public void testReduceTwoArgs() {
        // 计算集合中元素累加的总和
        List<Integer> numberList = Arrays.asList(1, 2, 3, 4, 5, 6, 7);

        // 准备用于累加的初始变量
        int result = 0;

        // Lambda 表达式对应的抽象方法：R apply(T t, U u);
        // T t ---> prevResult：前面累加的结果
        // U u ---> number：集合遍历的每一个元素

        Integer sumResult = numberList.stream()
                .reduce(result, (prevResult, number) -> {
                    return prevResult += number;
                });

        System.out.println("sumResult = " + sumResult);
    }

    @Test
    public void testReduceOneArg() {
        // 计算集合中元素累加的总和
        List<Integer> numberList = Arrays.asList(1, 2, 3, 4, 5, 6, 7);

        // Lambda 表达式对应的抽象方法：R apply(T t, U u);
        // T t ---> prevResult：前面累加的结果
        // U u ---> number：集合遍历的每一个元素

        // 和上面测试方法中两个参数的 reduce() 方法的区别是：
        // 区别1：返回是 Optional 类型，因为此时不确定集合中是否有元素
        // 区别2：把集合中第一个元素当做累加初始值来使用，后面的数据累加到前面的结果上
        Optional<Integer> optional = numberList.stream()
                .reduce((prevNumber, nextNumber) -> {
                    return prevNumber += nextNumber;
                });

        Integer sumResult = optional.get();
        System.out.println("sumResult = " + sumResult);
    }

    @Test
    public void testCollectorToList() {
        // 把原来的集合中偶数取出来，组成一个新集合返回
        List<Integer> numberList = Arrays.asList(1, 2, 3, 4, 5, 6, 7);

        List<Integer> evenNumberList = numberList.stream()
                .filter(number -> {
                    return number % 2 == 0;
                })
                .collect(Collectors.toList()); // 把 Stream 对集合处理之后得到的数据封装为一个新集合

        System.out.println("evenNumberList = " + evenNumberList);
    }

    @Test
    public void testCollectorToSet() {
        // 把原来的集合中偶数取出来，组成一个新集合返回
        List<Integer> numberList = Arrays.asList(1, 2, 3, 4, 5, 6, 7);

        Set<Integer> evenNumberSet = numberList.stream()
                .filter(number -> {
                    return number % 2 == 0;
                })
                .collect(Collectors.toSet()); // 把 Stream 对集合处理之后得到的数据封装为一个新集合

        System.out.println("evenNumberSet = " + evenNumberSet);
    }

    @Test
    public void testCollectorToMap() {
        // 把原来的集合中偶数取出来，组成一个新集合返回
        List<Integer> numberList = Arrays.asList(1, 2, 3, 4, 5, 6, 7);

        Map<String, Integer> map = numberList.stream()
                .filter(number -> {
                    return number % 2 == 0;
                })
                .collect(
                        Collectors.toMap(
                                number -> { return number + ""; }, // 封装逻辑：如何根据 Stream 中当前数据中的每一个生成 Map 的 Key
                                number -> { return number * 10; } // 封装逻辑：如何根据 Stream 中当前数据中的每一个生成 Map 的 Value
                        ));

        System.out.println(map);
    }

    @Test
    public void testStreamReview() {
        List<Employee> employeeList = new ArrayList<>();
        employeeList.add(new Employee(1, "tom", 5000.00d));
        employeeList.add(new Employee(2, "jerry", 6000.00d));
        employeeList.add(new Employee(3, "harry", 7000.00d));
        employeeList.add(new Employee(4, "bob", 8000.00d));
        employeeList.add(new Employee(5, "kate", 9000.00d));
        employeeList.add(new Employee(6, "mary", 9100.00d));
        employeeList.add(new Employee(7, "jim", 9200.00d));
        employeeList.add(new Employee(8, "white", 9300.00d));
        employeeList.add(new Employee(9, "black", 9400.00d));

        // 先给所有人的工资乘以10，然后筛选出工资大于90000且名字中有"a"的员工
        List<Employee> list = employeeList.stream()
                .map((employee) -> {
                    Double empSalary = employee.getEmpSalary();
                    employee.setEmpSalary(empSalary * 10);
                    return employee;
                })
                .filter(employee -> {
                    return employee.getEmpSalary() > 90000 && employee.getEmpName().contains("a");
                })
                .collect(Collectors.toList());

        // 遍历原来的集合
        for (Employee employee : employeeList) {
            System.out.println("旧数据：employee = " + employee);
        }

        // 遍历新集合
        for (Employee employee : list) {
            System.out.println("新数据：employee = " + employee);
        }
    }

}
